package cn.xsly.ymcc.service.impl;

import cn.xsly.ymcc.constants.MQConstants;
import cn.xsly.ymcc.domain.AlipayInfo;
import cn.xsly.ymcc.domain.PayFlow;
import cn.xsly.ymcc.domain.PayOrder;
import cn.xsly.ymcc.dto.AlipayNotifyDto;
import cn.xsly.ymcc.dto.PayParamDto;
import cn.xsly.ymcc.dto.PayResultVo;
import cn.xsly.ymcc.service.IAlipayInfoService;
import cn.xsly.ymcc.service.IPayFlowService;
import cn.xsly.ymcc.service.IPayOrderService;
import cn.xsly.ymcc.service.IPayService;
import cn.xsly.ymcc.util.AssertUtil;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class PayServiceImpl implements IPayService {
    @Autowired
    private IPayOrderService payOrderService;
    @Autowired
    private IAlipayInfoService alipayInfoService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IPayFlowService payFlowService;

    @Override
    public String pay(PayParamDto payParamDto) {
        PayOrder payOrder = payOrderService.selectByOrderSn(payParamDto.getOrderNo());
        AssertUtil.isNotNull(payOrder, "非法的请求");
        AssertUtil.isEqualsTrim(payOrder.getPayStatus(), 0, "订单已处理");
        // 1. 设置参数（全局只需设置一次）
        //去数据库查询
        AlipayInfo alipayInfo = alipayInfoService.selectById(2L);
        //判定回调的url
        String returnUrl = payParamDto.getCallUrl() != null ? payParamDto.getCallUrl() : alipayInfo.getReturnUrl();

        try {
            Factory.setOptions(getOptions(alipayInfo));
            //下单
            AlipayTradePagePayResponse response = Factory.Payment.Page().pay(payOrder.getSubject(), payOrder.getOrderNo(), payOrder.getAmount().toString(), returnUrl);

            payOrder.setPayStatus(1);//设置为支付中
            payOrder.setUpdateTime(new Date());
            payOrderService.updateById(payOrder);

            return response.getBody();//拉起收银台的form 表单
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "";
    }

    @Override
    public String notifyAliPay(AlipayNotifyDto alipayNotifyDto) {
        //1.验签
        Map map = JSON.parseObject(JSON.toJSONString(alipayNotifyDto), Map.class);
        Boolean aBoolean = null;
        try {
            aBoolean = Factory.Payment.Common().verifyNotify(map);
            if (!aBoolean) return "fail";
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }

        //2.根据支付宝返的订单号，查询自己订单，成功保存订单流水
        PayOrder payOrder = payOrderService.selectByOrderSn(alipayNotifyDto.getOut_trade_no());
        //3.付款完成，订单状态修改
        if (payOrder.getPayStatus().equals(AlipayNotifyDto.TRADE_FINISHED) ||
                payOrder.getPayStatus().equals(AlipayNotifyDto.TRADE_SUCCESS)) {
            Date date = new Date();
            payOrder.setUpdateTime(date);
            payOrder.setPayStatus(PayOrder.PAY_SUCCESS);
            //4.生成支付流水
            PayFlow payFlow = new PayFlow();
            payFlow.setNotifyTime(date);
            payFlow.setSubject(payOrder.getSubject());
            payFlow.setOutTradeNo(alipayNotifyDto.getOut_trade_no());
            payFlow.setTotalAmount(new BigDecimal(alipayNotifyDto.getTotal_amount()));
            payFlow.setTradeStatus(alipayNotifyDto.getTrade_status());
            //5.发送支付单和流水的消息
            Map<String, Object> resMap = new HashMap<>();
            resMap.put("payOrder", payOrder);
            resMap.put("payFlow", payFlow);

            PayResultVo resultVo = new PayResultVo(payOrder.getOrderNo(), payOrder.getExtParams());
            Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(resultVo)).build();
            TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                    MQConstants.TX_PRODUCER_PAY, MQConstants.TOPIC_PAY_TAGS_PAY,
                    message, resMap);
            if (!sendResult.getLocalTransactionState().equals(LocalTransactionState.COMMIT_MESSAGE)) {
                return "fail";
            }
        }
        return "success";
    }

    @Override
    @Transactional
    public void updatePayOrderAndPayFlow(PayOrder payOrder, PayFlow payFlow) {
        payOrderService.updateById(payOrder);
        payFlowService.insert(payFlow);
    }


    private Config getOptions(AlipayInfo alipayInfo) {
        Config config = new Config();
        config.protocol = alipayInfo.getProtocol();
        config.gatewayHost = alipayInfo.getGatewayHost();
        config.signType = alipayInfo.getSignType();
        config.appId = alipayInfo.getAppId();
        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        config.merchantPrivateKey = alipayInfo.getMerchantPrivateKey();
        //注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载
        config.alipayPublicKey = alipayInfo.getAlipayPublicKey();
        //可设置异步通知接收服务地址（可选）
        config.notifyUrl = alipayInfo.getNotifyUrl();
        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
        config.encryptKey = "aa4BtZ4tspm2wnXLb1ThQA==";
        return config;
    }
}
